package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.IntergralFeignApi;
import cn.wolfcode.feign.OrderPayFeignApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMQResult;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;

@Service
@Slf4j
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Value("${pay.returnUrl}")
    private String returnUrl;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;

    @Autowired
    private OrderPayFeignApi orderPayFeignApi;

    @Override
    @Transactional
    public String doSeckill(int time, Long seckillId, Long phone) {
        int count = seckillProductService.decrStockCount(seckillId);
        if(count == 0){
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        String orderNo = createOrderNo(time, seckillId, phone);
        return orderNo;
    }


    /**
     * 创建订单
     * @param time 秒杀场次
     * @param seckillId 秒杀商品id
     * @return 订单号
     */
    private String createOrderNo(int time, Long seckillId, Long phone) {
        //创建订单
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserId(phone);
        //获取缓存商品信息
        SeckillProductVo vo = seckillProductService.find(time, seckillId);
        orderInfo.setProductId(vo.getProductId());
        orderInfo.setDeliveryAddrId(1L);
        orderInfo.setProductName(vo.getProductName());
        orderInfo.setProductImg(vo.getProductImg());
        orderInfo.setProductCount(1);
        orderInfo.setProductPrice(vo.getProductPrice());
        orderInfo.setSeckillPrice(vo.getSeckillPrice());
        orderInfo.setIntergral(vo.getIntergral());
        orderInfo.setCreateDate(new Date());
        orderInfo.setSeckillDate(new Date());
        orderInfo.setSeckillTime(vo.getTime());
        orderInfo.setSeckillId(vo.getId());
        orderInfo.setOrderNo(IdGenerateUtil.get().nextId()+"");
        orderInfoMapper.insert(orderInfo);
        return orderInfo.getOrderNo();
    }

    @Override
    public OrderInfo find(String orderNo) {
        //查询redis中的订单信息
        Object objJson = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey(""), orderNo);
        return JSON.parseObject(objJson + "", OrderInfo.class);
    }

    @Override
    @Transactional
    public void seckillOrderTimeout(OrderMQResult orderMQResult) {
        //判断订单状态是否支付
        OrderInfo orderInfo = orderInfoMapper.find(orderMQResult.getOrderNo());
        if(orderInfo != null){
            if(orderInfo.getStatus().equals(OrderInfo.STATUS_ARREARAGE)){
                //回补真实库存
                seckillProductService.stockCountBack(orderMQResult.getSeckillId());
                //回补预库存
                seckillProductService.syncRedisStockCount(orderMQResult.getSeckillId(), orderMQResult.getTime());
                //修改本地标识
                rocketMQTemplate.syncSend(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, orderMQResult.getSeckillId());
                //修改订单状态
                int count = orderInfoMapper.updateCancelStatus(orderMQResult.getOrderNo(), OrderInfo.STATUS_TIMEOUT);
                if(count == 0){
                    //超时取消失败,可以用户在还没有修改状态的时候支付成功,需要抛出异常捕获
                    throw new BusinessException(SeckillCodeMsg.CANCEL_ORDER_ERROR);
                }
            }
        }
    }

    @Override
    public String payOnline(String orderNo) {
        //查询订单
        OrderInfo orderInfo = this.find(orderNo);
        //封装支付参数
        PayVo payVo = new PayVo();
        payVo.setOutTradeNo(orderNo);
        payVo.setTotalAmount(orderInfo.getSeckillPrice()+"");
        payVo.setSubject(orderInfo.getProductName());
        payVo.setBody(orderInfo.getProductName());
        payVo.setReturnUrl(returnUrl);
        payVo.setNotifyUrl(notifyUrl);
        //远程调用支付服务接口进行支付
        Result<String> result = orderPayFeignApi.pay(payVo);
        if(result != null && !result.hasError()){
            return result.getData();
        }
        throw new BusinessException(SeckillCodeMsg.PAY_SERVER_ERROR);
    }

    @Override
    public void payOnlineSuccess(String orderNo) {
        log.info("进入支付成功业务...");
        //查询订单信息
        OrderInfo orderInfo = this.find(orderNo);
        //封装支付成功流水记录
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderNo);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        payLog.setNotifyTime(sdf.format(new Date()));
        payLog.setTotalAmount(orderInfo.getSeckillPrice()+"");
        payLog.setPayType(OrderInfo.PAYTYPE_ONLINE);
        payLogMapper.insert(payLog);
        //修改订单状态
        int count = orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_ONLINE);
        if(count == 0){
            log.info("进入支付失败退款...");
        }
    }

    @Override
    public void alipayRefund(OrderInfo orderInfo) {
        log.info("进入支付退款流程");
        //增加退款流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());
        refundLog.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundLog.setRefundReason("no");
        refundLog.setRefundType(orderInfo.getPayType());
        refundLog.setRefundTime(new Date());
        refundLogMapper.insert(refundLog);

        //封装退款信息
        RefundVo refundVo = new RefundVo();
        refundVo.setOutTradeNo(orderInfo.getOrderNo());
        refundVo.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundVo.setRefundReason("no");
        //远程调用支付服务退款接口
        Result<Boolean> result = orderPayFeignApi.refund(refundVo);
        if(result != null && !result.hasError()){
            if(result.getData()){
                //退款成功
                //修改订单状态
                orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_REFUND);
                //回补真实库存
                seckillProductService.stockCountBack(orderInfo.getSeckillId());
                //回补预库存
                seckillProductService.syncRedisStockCount(orderInfo.getSeckillId(), orderInfo.getSeckillTime());
                //修改本地标识
                rocketMQTemplate.syncSend(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, orderInfo.getSeckillId());
            }else{
                throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
            }
        }
    }

    @Override
    public void cancelOrder(OrderInfo orderInfo) {
        //回补真实库存
        seckillProductService.stockCountBack(orderInfo.getSeckillId());
        //回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillId(), orderInfo.getSeckillTime());
        //修改本地标识
        rocketMQTemplate.syncSend(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, orderInfo.getSeckillId());
        //修改订单状态为手动取消订单
        orderInfoMapper.changeCancelStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_CANCEL);
    }

    @Autowired
    private IntergralFeignApi intergralFeignApi;

    @Override
    @GlobalTransactional
    public void payIntergral(String orderNo) {
        OrderInfo orderInfo = this.find(orderNo);
        if(orderInfo == null){
            throw new BusinessException(SeckillCodeMsg.PARAM_ERROR);
        }
        //插入流水记录
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderNo);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        payLog.setNotifyTime(sdf.format(new Date()));
        payLog.setTotalAmount(orderInfo.getSeckillPrice()+"");
        payLog.setPayType(OrderInfo.PAYTYPE_INTERGRAL);
        payLogMapper.insert(payLog);
        //远程调用积分服务,减少积分
        OperateIntergralVo vo = new OperateIntergralVo();
        vo.setInfo("hello");
        vo.setPk(orderNo);
        vo.setUserId(orderInfo.getUserId());
        vo.setValue(orderInfo.getIntergral());
        Result<String> result = intergralFeignApi.payIntergral(vo);
        if(result == null){
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_ERROR);
        }
        if(result.hasError()){
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }
        //修改订单状态
        int count = orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_INTERGRAL);
        if(count == 0){
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }
    }

    @Override
    @GlobalTransactional
    public void intergralRefund(OrderInfo orderInfo) {
        //增加退款流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());
        refundLog.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundLog.setRefundReason("no");
        refundLog.setRefundType(orderInfo.getPayType());
        refundLog.setRefundTime(new Date());
        refundLogMapper.insert(refundLog);
        //远程调用积分服务,增加积分
        OperateIntergralVo vo = new OperateIntergralVo();
        vo.setInfo("no");
        vo.setPk(orderInfo.getOrderNo());
        vo.setUserId(orderInfo.getUserId());
        vo.setValue(orderInfo.getIntergral());
        Result<String> result = intergralFeignApi.refundIntergral(vo);
        if(result == null || result.hasError()){
            throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
        }

        //修改订单状态
        int count = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_REFUND);
        if(count == 0){
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }
        //回补真实库存
        seckillProductService.stockCountBack(orderInfo.getSeckillId());
        //回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillId(), orderInfo.getSeckillTime());
        //修改本地标识
        rocketMQTemplate.syncSend(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, orderInfo.getSeckillId());
    }
}
